import json
import os
import requests
from typing import List

from utils import tools
from utils.single_data import SingleData
from utils.apk_download import Download

url_c = tools.tools.collection_url
url_w = tools.tools.work_url
share_folder = r'D:\Useless\Share'


class Req:
    name = 'parent'
    name_zh = '父'
    url_c = tools.tools.collection_url
    url_w = tools.tools.work_url
    params = tools.tools.params
    _path = r'D:\Useless\Share'

    parent_id = None
    project_id = None
    conf_file = None
    conf_dict = {}

    @staticmethod
    def req(url, parent_id, project_id):

        headers = tools.req_param.headers
        params = tools.tools.params
        params['_parentId'] = parent_id
        params['_projectId'] = project_id

        tools.log.debug(f'请求接口: {url}')
        tools.log.debug(f'请求头: {headers}')
        tools.log.debug(f'请求参数: {params}')

        _res = requests.get(url=url, headers=headers, params=params)
        _json = _res.json()
        tools.log.debug(f'响应信息: {_json}')
        tools.log.debug(f'响应Json: {json.dumps(_json)}')
        tools.log.debug(' -_- ' * 50)

        return _json

    def mk_dir(self, *folder_names):
        """
        根据 parent_id 创建文件夹
        """
        _path_li = [self._path]
        _path_li.extend(folder_names)
        _path = os.sep.join(_path_li)
        try:
            os.makedirs(_path)
            tools.log.debug(f'文件夹 << {_path} >> 创建成功')
        except FileExistsError:
            tools.log.debug(f'文件夹 << {_path} >> 已经存在, 无需创建')

    def all_folder(self, parent_id, project_id):

        # di 用于存储目录关系, 目录 id : 目录 其他信息
        di = self.conf_dict

        # 文件夹: ( collection )
        _res_coll = self.req(self.url_c, parent_id, project_id)
        if isinstance(_res_coll, List):
            tools.tools.cookie_useful(True)
            for coll in _res_coll:
                if 'collection' == coll.get('objectType') and tools.tools.default_time < tools.tools.date2time(coll.get('updated')):
                    _time = tools.tools.date2time(coll.get('updated'))
                    _date = tools.tools.time2date(_time)
                    di.update({coll.get('_id'): {
                        'parent_id': coll.get('_parentId'),
                        'title': coll.get('title'),
                        'update_time': _time,
                        'update_date': _date,
                        'creator': coll.get('creator').get('name'),
                        'apks': []
                    }})
                    # 递归获取所有子集文件夹:
                    if int(coll.get('collectionCount')) > 0 or int(coll.get('workCount')) > 0:
                        self.all_folder(coll.get('_id'), project_id)
        else:
            # cookies 可能失效了
            # print('目录接口返回值:', _res_coll)
            tools.log.debug(f'目录接口返回值: {_res_coll}')
            tools.tools.cookie_useful(False)

        # 文件: ( work )
        _res_work = self.req(self.url_w, parent_id, project_id)
        work_li = []
        work_parent_id = parent_id
        if isinstance(_res_work, List):
            for work in _res_work:
                work_parent_id = work.get('_parentId')
                work_di = {}
                if 'work' == work.get('objectType') \
                        and tools.tools.default_time < tools.tools.date2time(work.get('updated')) \
                        and 'apk' == work.get('fileType'):
                    _time = tools.tools.date2time(work.get('updated'))
                    _date = tools.tools.time2date(_time)
                    work_di['creator'] = work.get('creator').get('name')
                    work_di['download_url'] = work.get('downloadUrl')
                    work_di['file_name'] = work.get('fileName')
                    work_di['preview_url'] = work.get('previewUrl')
                    work_di['update_time'] = _time
                    work_di['update_date'] = _date
                    work_di['id'] = work.get('_id')
                    work_di['parent_id'] = work.get('_parentId')
                    _time = tools.tools.date2time(work.get('updated'))
                    _date = tools.tools.time2date(_time)
                    work_li.append(work_di)

        # 向配置文件中写入文件夹和安装包数据 :
        if di.get(work_parent_id):
            di.get(work_parent_id)['apks'] = work_li
        tools.tools.write(self.conf_file, di)

        return di

    def make_all(self):
        di = self.all_folder(self.parent_id, self.project_id, )

        for k, v in di.items():
            # 顶层 :
            if v.get('parent_id') == self.parent_id:
                if self.name == 'manage' or self.name == 'h':
                    # print(['3_健管版APP', v.get('title')])
                    self.mk_dir(v.get('title'))
                if self.name == 'h_health':
                    # print('路径列表:', ['4_全病程', '医链健康-APP', v.get('title')])
                    # print('路径:', self._path)
                    tools.log.debug(f'路径列表: {['4_全病程', '医链健康-APP', v.get('title')]}')
                    tools.log.debug(f'路径: {self._path}')
                    self.mk_dir(v.get('title'))
            # 非顶层 :
            else:
                _li = []
                _parent_id = v.get('parent_id')
                _li.append(v.get('title'))
                while di.get(_parent_id):
                    _li.append(di.get(_parent_id).get('title'))
                    _parent_id = di.get(_parent_id).get('parent_id')
                # print(f'{self.name}_文件夹层级:', _li[::-1])
                tools.log.debug(f'{self.name}_文件夹层级: {_li[::-1]}')
                """
                因为需要结合配置文件, 所以代码看起来比较绕,
                思路:
                    1. 递归获取所有目录, 存储为字典, 字典中体现出层级关系 ( id, parent_id, title )
                    2. 遍历字典, 如果 parent_id 找不到数据, 则表示没有上层文件夹, 不进行处理 ( 或者创建该文件夹 )
                    3. 如果 parent_id 找到数据, 则表示有上层文件夹, 则继续往上层找, 每层存到列表中, 直到没有上层
                    4. 反转列表, 进行创建, 反转后, 列表顺序就是文件夹的顺序, 只需要调用 os.makedirs() 即可完成创建
                问题:
                    健管师和其他不一样, 不存在顶层, 直接创建即可.
                    因此健管端重新该方法...
                """
                if self.name == 'h':
                    self.mk_dir(*_li[::-1])
                else:
                    self.mk_dir(*_li[::-1][1:])
        return di

    def download_all(self):
        # 先把文件夹创建好:
        di = self.make_all()

        # di = tools.tools.get_all('apk_doctor')
        _di = {}
        # print(f'{self.name_zh} 下新包信息:', json.dumps(di))
        tools.log.debug(f'{self.name_zh} 下新包信息: {json.dumps(di)}')

        # 直接加载配置文件, 或者使用上一步的返回值:
        for k, v in di.items():
            if v.get('parent_id') == self.parent_id:
                if self.name == 'manage':
                    _folder = os.sep.join([share_folder, '3_健管版APP', v.get('title')])
                    apks = v.get('apks')
                    for apk in apks:
                        _apk_path = os.sep.join([share_folder, '3_健管版APP', v.get('title'), apk.get('file_name'), ])
                        print(_apk_path)
                        _download = Download(
                            apk.get('file_name'),
                            apk.get('update_time'),
                            apk.get('update_date'),
                            apk.get('download_url'),
                            _apk_path,
                            file_path_li=['3_健管版APP', v.get('title')]
                        )
                        _download.run()
                elif self.name == 'h':
                    _folder = os.sep.join([share_folder, '4_全病程APP', v.get('title')])
                    apks = v.get('apks')
                    for apk in apks:
                        _apk_path = os.sep.join([share_folder, '4_全病程APP', v.get('title'), apk.get('file_name'), ])
                        print(_apk_path)
                        _download = Download(
                            apk.get('file_name'),
                            apk.get('update_time'),
                            apk.get('update_date'),
                            apk.get('download_url'),
                            _apk_path,
                            file_path_li=['4_全病程APP', v.get('title')]
                        )
                        _download.run()
                # 全病程/患者端 顶层
                elif self.name == 'h_health':
                    # 全病程 / 患者, 顶层为: D:\Useless\Share\4_全病程APP\医链健康-APP, 该目录下分为 test/pre/prod 三层, 该 if 是加载到这三层目录内, 因此需要进行下载
                    _folder = os.sep.join([share_folder, '4_全病程APP', '医链健康-APP', v.get('title')])
                    # print('4_全病程APP----医链健康-APP:', _folder)
                    tools.log.debug(f'4_全病程APP----医链健康-APP: {_folder}')
                    apks = v.get('apks')
                    for apk in apks:
                        _apk_path = os.sep.join([share_folder, '4_全病程APP', '医链健康-APP', v.get('title'), apk.get('file_name'), ])
                        print(_apk_path)
                        _download = Download(
                            apk.get('file_name'),
                            apk.get('update_time'),
                            apk.get('update_date'),
                            apk.get('download_url'),
                            _apk_path,
                            file_path_li=['4_全病程APP', '医链健康-APP', v.get('title')]
                        )
                        _download.run()

                else:
                    # print('医生端和患者端顶层就不进行创建和下载了')
                    tools.log.debug('医生端和患者端顶层就不进行创建和下载了')
            else:
                # Share 目录, 拼接 _li 后, 再拼接文件的 parent_id, 再拼接文件自己的文件名.
                _li = []  # _li 用于保存 Share 目录到文件所在目录之间的所有层级目录
                r"""
                比如: 
                    D:\Useless\Share\4_全病程APP\医链健康-APP\test\折叠屏\app-yljk_fold.apk
                    Share 目录:        D:\Useless\Share
                    _li 列表:          ['4_全病程APP', '医链健康-APP', 'test']
                    apk 上层和自己:     (折叠屏) 和 (app-yljk_fold.apk)
                该 else 分支下, 是非顶层的情况, 因此需要循环向上层遍历
                """
                if self.name == 'doctor':
                    _li = ['1_执业版APP']
                elif self.name == 'health':
                    _li = ['2_患者版APP']
                elif self.name == 'h':
                    _li = ['4_全病程APP']
                elif self.name == 'h_health':
                    _li = ['4_全病程APP', '医链健康-APP']

                _parent_id = v.get('parent_id')
                while di.get(_parent_id):
                    # _parent_id 最高拿到的是 _li 定义的最后一个元素对应的目录, 全病程患者端对应: ['4_全病程APP', '医链健康-APP'] 中的 医链健康-APP
                    _li.append(di.get(_parent_id).get('title'))
                    _parent_id = di.get(_parent_id).get('parent_id')
                    _di[k] = _li

                if self.name == 'doctor' or self.name == 'health':
                    # 执业版 和 患者版, 删除顶层目录, 执业版为例: 删除 "执业版 - APP" 目录, 因为该目录已经在本地 Share 目录定义成 "1_执业版APP"
                    if len(di[k]) > 1 and _di.get(k):
                        _di[k].pop(1)
                if self.name == 'h_health':
                    if len(di[k]) > 1 and _di.get(k):
                        _di[k].pop(1)

                if _di.get(k):
                    _di[k].append(di.get(k).get('title'))
                else:
                    _li.append(di.get(k).get('title'))
                    _di[k] = _li
                # print('文件夹 id 与文件目录:', _di)
                tools.log.debug(f'文件夹 id 与文件目录: {_di}')

                if v.get('apks'):
                    for apk_di in v.get('apks'):
                        folder_li = _di.get(apk_di.get('parent_id'))
                        folder_li = folder_li if folder_li else []
                        tools.log.debug(f'apk下载目录: {folder_li}')
                        _apk_path = os.sep.join([share_folder, *folder_li, apk_di.get('file_name'), ])
                        tools.log.debug(f'apk下载路径: {_apk_path}')
                        _download = Download(
                            apk_di.get('file_name'),
                            apk_di.get('update_time'),
                            apk_di.get('update_date'),
                            apk_di.get('download_url'),
                            _apk_path,
                            file_path_li=folder_li
                        )
                        _download.run()


class Doctor(Req):
    name = 'doctor'
    name_zh = '执业版'

    _path = os.sep.join([share_folder, '1_执业版App'])

    parent_id = tools.tools.get_id('doctor_parent_id')
    project_id = tools.tools.get_id('doctor_project_id')
    __project_id = tools.tools.get_id('doctor_project_id')
    __parent_id = tools.tools.get_id('doctor_parent_id')

    conf_file = os.sep.join([os.path.dirname(os.path.dirname(__file__)), 'conf', 'apk_doctor.yml'])
    conf_dict = SingleData.doctor


class Health(Req):
    name = 'health'
    name_zh = '患者版'

    _path = os.sep.join([share_folder, '2_患者版APP'])

    project_id = tools.tools.get_id('health_project_id')
    parent_id = tools.tools.get_id('health_parent_id')

    __project_id = tools.tools.get_id('health_project_id')
    __parent_id = tools.tools.get_id('health_parent_id')

    conf_file = os.sep.join([os.path.dirname(os.path.dirname(__file__)), 'conf', 'apk_health.yml'])
    conf_dict = SingleData.health


class Manage(Req):
    name = 'manage'
    name_zh = '健管版'

    _path = os.sep.join([share_folder, '3_健管版APP'])

    project_id = tools.tools.get_id('manage_project_id')
    parent_id = tools.tools.get_id('manage_parent_id')

    __project_id = tools.tools.get_id('management_project_id')
    __parent_id = tools.tools.get_id('management_parent_id')

    conf_file = os.sep.join([os.path.dirname(os.path.dirname(__file__)), 'conf', 'apk_manage.yml'])
    conf_dict = SingleData.manage

    # def make_all(self):
    #     di = self.all_folder(self.parent_id, self.project_id, )
    #
    #     for k, v in di.items():
    #         if v.get('parent_id') == self.parent_id:
    #             self.mk_dir(v.get('title'))
    #             print(['3_健管版APP', v.get('title')])
    #         else:
    #             _li = []
    #             _parent_id = v.get('parent_id')
    #             _li.append(v.get('title'))
    #             while di.get(_parent_id):
    #                 _li.append(di.get(_parent_id).get('title'))
    #                 _parent_id = di.get(_parent_id).get('parent_id')
    #             print(_li[::-1])
    #             """
    #             因为需要结合配置文件, 所以代码看起来比较绕,
    #             思路:
    #                 1. 递归获取所有目录, 存储为字典, 字典中体现出层级关系 ( id, parent_id, title )
    #                 2. 遍历字典, 如果 parent_id 找不到数据, 则表示没有上层文件夹, 不进行处理 ( 或者创建该文件夹 )
    #                 3. 如果 parent_id 找到数据, 则表示有上层文件夹, 则继续往上层找, 每层存到列表中, 直到没有上层
    #                 4. 反转列表, 进行创建, 反转后, 列表顺序就是文件夹的顺序, 只需要调用 os.makedirs() 即可完成创建
    #             问题:
    #                 健管师和其他不一样, 不存在顶层, 直接创建即可.
    #                 因此健管端重新该方法...
    #             """
    #             self.mk_dir(*_li[::-1])


class H(Req):
    name = 'h'
    name_zh = '全病程'

    _path = os.sep.join([share_folder, '4_全病程APP'])

    project_id = tools.tools.get_id('h_project_id')
    parent_id = tools.tools.get_id('h_parent_id')

    conf_file = os.sep.join([os.path.dirname(os.path.dirname(__file__)), 'conf', 'apk_h.yml'])
    conf_dict = SingleData.h
    pass


# 全病程下的患者端
class HHealth(Req):
    name = 'h_health'
    name_zh = '全病程的患者版'

    _path = os.sep.join([share_folder, '4_全病程APP', '医链健康-APP'])

    project_id = tools.tools.get_id('h_health_project_id')
    parent_id = tools.tools.get_id('h_health_parent_id')

    __project_id = tools.tools.get_id('h_health_project_id')
    __parent_id = tools.tools.get_id('h_health_parent_id')

    conf_file = os.sep.join([os.path.dirname(os.path.dirname(__file__)), 'conf', 'apk_h_health.yml'])
    conf_dict = SingleData.h_health


if __name__ == '__main__':
    doctor = Doctor()
    health = Health()
    manage = Manage()
    h = H()
    h_health = HHealth()

    """
    # doctor.all_collection()
    doctor.all_folder(tools.tools.get_id('doctor_parent_id'), tools.tools.get_id('doctor_project_id'), )
    health.all_folder(tools.tools.get_id('health_parent_id'), tools.tools.get_id('health_project_id'), )
    manage.all_folder(tools.tools.get_id('manage_parent_id'), tools.tools.get_id('manage_project_id'), )
    # """

    # """
    # doctor.download_all()
    # health.download_all()
    # manage.download_all()
    # h.download_all()
    # h_health.make_all()
    h_health.download_all()
    # """

    """
    doctor.make_all()
    health.make_all()
    manage.make_all()
    # """

    """
    import json

    # print(json.dumps(Doctor().get_index(tools.tools.get_id('doctor_parent_id'), tools.tools.get_id('doctor_project_id'))))
    # print(json.dumps(Health().get_index(tools.tools.get_id('doctor_parent_id'), tools.tools.get_id('doctor_project_id'))))
    # print(json.dumps(Management().get_index(tools.tools.get_id('doctor_parent_id'), tools.tools.get_id('doctor_project_id'))))

    # doctor.mk_dir('a', 'b', 'vb')
    # """
